package com.yike.user.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yike.common.constant.CommonConstant;
import com.yike.common.exception.BusinessException;
import com.yike.common.redis.RedisUtil;
import com.yike.common.tool.CommonUtil;
import com.yike.common.tool.LoginUtil;
import com.yike.common.tool.StringUtil;
import com.yike.common.tool.TokenUtil;
import com.yike.common.vo.LoginUserInfoVo;
import com.yike.user.convert.UserConvert;
import com.yike.user.entity.Agent;
import com.yike.user.entity.Merchant;
import com.yike.user.entity.User;
import com.yike.user.entity.UserAuthorize;
import com.yike.user.mapper.AgentMapper;
import com.yike.user.mapper.MerchantMapper;
import com.yike.user.mapper.UserAuthorizeMapper;
import com.yike.user.mapper.UserMapper;
import com.yike.user.param.AgentBindPhoneParam;
import com.yike.user.param.AgentBindWxParam;
import com.yike.user.param.GetAppCodeParam;
import com.yike.user.param.LoginParam;
import com.yike.user.service.LoginService;
import com.yike.user.strategy.login.source.LoginSourceContext;
import com.yike.user.strategy.login.type.LoginTypeContext;
import com.yike.user.utils.WxAgentAppUtil;
import com.yike.user.utils.WxAppUtil;
import com.yike.user.utils.WxMchAppUtil;
import com.yike.user.vo.wx.WxAppLoginVo;
import com.yike.user.vo.wx.WxPhoneVo;
import lombok.extern.java.Log;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.util.Date;
import java.util.UUID;

/**
 * @author Sakura
 * @date 2024/8/20 10:28
 */
@Service
@Log
public class LoginServiceImpl implements LoginService {

    @Autowired
    private LoginTypeContext loginTypeContext;
    @Autowired
    private LoginSourceContext loginSourceContext;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private WxAppUtil wxAppUtil;
    @Autowired
    private WxMchAppUtil wxMchAppUtil;
    @Autowired
    private WxAgentAppUtil wxAgentAppUtil;
    @Autowired
    private CommonUtil commonUtil;
    @Autowired
    private AgentMapper agentMapper;
    @Autowired
    private MerchantMapper merchantMapper;
    @Autowired
    private UserAuthorizeMapper userAuthorizeMapper;

    @Override
    public LoginUserInfoVo login(LoginParam loginParam) throws Exception {
        // 获取登录用户
        User user = loginTypeContext.login(loginParam);
        // 验证用户状态
        if (user.getStatus() == 2) {
            throw new BusinessException("该账号已被禁用");
        }
        if (user.getStatus() == 3 || user.getStatus() == 4) {
            throw new BusinessException("该账号已被冻结");
        }

        // 更新登录时间
        user.setLoginTime(new Date());
        userMapper.updateById(user);

        // 封装登录信息返回给前端
        LoginUserInfoVo loginUserVo = UserConvert.INSTANCE.convert(user);

        // 处理不同端登录需要不同信息问题
        loginSourceContext.login(loginUserVo, loginParam.getLoginSource());

        // 登录成功保存token信息
        String token = UUID.randomUUID().toString();
        loginUserVo.setToken(token);
        // 目前设置为30天有效后面再调
        redisUtil.set(token, loginUserVo, 30 * 24 * 60 * 60);
        // 此处为了兼容websocket认证，误删
        redisUtil.set("ws_" + user.getId().toString(), token, 30 * 24 * 60 * 60);

        // 保存用户登录token，用户修改密码后删除
        LoginUtil.saveUserLoginToken(user.getId(), token);

        return loginUserVo;
    }

    @Override
    public LoginUserInfoVo agentBindPhone(AgentBindPhoneParam agentBindPhoneParam) throws Exception {
        // 手机号和验证码不能为空
        if (StringUtil.isEmpty(agentBindPhoneParam.getMobile()) || StringUtil.isEmpty(agentBindPhoneParam.getSmsCode())) {
            throw new BusinessException(500, "手机号或验证码不能为空");
        }
        // 如果验证码666666则不做校验
        if (!"666666".equals(agentBindPhoneParam.getSmsCode())) {
            // 校验短信验证码是否正确
            if (!commonUtil.checkCode(CommonConstant.SMS_CODE + agentBindPhoneParam.getMobile(),
                    agentBindPhoneParam.getSmsCode())) {
                throw new BusinessException(500, "短信验证码错误");
            }
        }
        // 获取登录用户信息
        LoginUserInfoVo loginUserInfoVo = (LoginUserInfoVo) redisUtil.get(agentBindPhoneParam.getToken());
        if (ObjectUtil.isNull(loginUserInfoVo)){
            throw new BusinessException(500, "token信息异常");
        }

        // 判断手机号是否已注册代理商
        User agentUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getMobile, agentBindPhoneParam.getMobile()));
        if (agentUser == null) {
            throw new BusinessException(500, "当前手机号还未成为代理商，请联系平台客服成为代理商");
        }
        Agent agent = agentMapper.selectOne(Wrappers.lambdaQuery(Agent.class)
                .eq(Agent::getUserId, agentUser.getId()));
        if (agent == null) {
            throw new BusinessException(500, "当前手机号还未成为代理商，请联系平台客服成为代理商");
        }
        // 判断当前手机号用户是否已绑定微信
        // 先判断是否已存在信息
        UserAuthorize openIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                .eq(UserAuthorize::getSource, 3)
                .eq(UserAuthorize::getUserId, agentUser.getId())
                .eq(UserAuthorize::getType, 2));
        if (ObjectUtil.isNotNull(openIdAuthorize)) {
            throw new BusinessException(500, "当前手机号已绑定其它微信号，如需换绑请联系平台客服");
        }
        // 将微信绑定信息切换到新的手机号用户
        openIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                .eq(UserAuthorize::getSource, 3)
                .eq(UserAuthorize::getUserId, loginUserInfoVo.getId())
                .eq(UserAuthorize::getType, 2));
        if (ObjectUtil.isNull(openIdAuthorize)) {
            throw new BusinessException(500, "获取微信授权信息异常");
        }
        // 直接替换掉用户ID
        openIdAuthorize.setUserId(agentUser.getId());
        userAuthorizeMapper.updateById(openIdAuthorize);

        // 判断是否有对应的unionID
        UserAuthorize unionIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                .eq(UserAuthorize::getSource, 3)
                .eq(UserAuthorize::getUserId, loginUserInfoVo.getId())
                .eq(UserAuthorize::getType, 3));
        if (ObjectUtil.isNotNull(unionIdAuthorize)) {
            // 直接替换掉
            unionIdAuthorize.setUserId(agentUser.getId());
            userAuthorizeMapper.updateById(unionIdAuthorize);
        }

        // 更新用户信息
        BeanUtils.copyProperties(agentUser, loginUserInfoVo);
        // 处理不同端登录需要不同信息问题
        loginSourceContext.login(loginUserInfoVo, 3);

        redisUtil.set(agentBindPhoneParam.getToken(), loginUserInfoVo, 30 * 24 * 60 * 60);

        return loginUserInfoVo;
    }

    @Override
    public boolean getWxPhone(String code) throws Exception {
        // 从微信接口获取手机号
        WxPhoneVo wxPhoneVo = wxAppUtil.getWxPhone(code);
        // 需要校验当前手机号是否已存在用户
        // 获取当前登录用户信息
        User user = userMapper.selectById(LoginUtil.getUserId());
        // 判断手机号是否为空，为空则更新
        if (StringUtil.isBlank(user.getMobile())) {
            // 此处添加逻辑，如果当前手机号不存在用户直接绑定，如果存在则切换用户到
            User mobileUser = userMapper.selectOne(Wrappers.<User>lambdaQuery()
                    .eq(User::getMobile, wxPhoneVo.getPhone_info().getPurePhoneNumber())
                    .ne(User::getStatus, 0));
            if (mobileUser != null) {
                // 将微信绑定信息切换到新的手机号用户
                UserAuthorize openIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                        .eq(UserAuthorize::getSource, 1)
                        .eq(UserAuthorize::getUserId, LoginUtil.getUserId())
                        .eq(UserAuthorize::getType, 2));
                if (ObjectUtil.isNull(openIdAuthorize)) {
                    throw new BusinessException(500, "获取微信授权信息异常");
                }
                // 直接替换掉用户ID
                openIdAuthorize.setUserId(mobileUser.getId());
                userAuthorizeMapper.updateById(openIdAuthorize);

                // 判断是否有对应的unionID
                UserAuthorize unionIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                        .eq(UserAuthorize::getSource, 1)
                        .eq(UserAuthorize::getUserId, LoginUtil.getUserId())
                        .eq(UserAuthorize::getType, 3));
                if (ObjectUtil.isNotNull(unionIdAuthorize)) {
                    // 直接替换掉
                    unionIdAuthorize.setUserId(mobileUser.getId());
                    userAuthorizeMapper.updateById(unionIdAuthorize);
                }

                // 获取登录用户信息
                LoginUserInfoVo loginUserInfoVo = LoginUtil.getLoginUserInfoVo();

                // 更新用户信息
                BeanUtils.copyProperties(mobileUser, loginUserInfoVo);
                // 处理不同端登录需要不同信息问题
                loginSourceContext.login(loginUserInfoVo, 1);

                redisUtil.set(TokenUtil.getToken(), loginUserInfoVo, 30 * 24 * 60 * 60);
            } else {
                user.setMobile(wxPhoneVo.getPhone_info().getPurePhoneNumber());
                userMapper.updateById(user);
            }
        } else {
            if (!user.getMobile().equals(wxPhoneVo.getPhone_info().getPurePhoneNumber())) {
                throw new BusinessException("手机号不匹配");
            }
        }
        return true;
    }

    @Override
    public String agentBindWx(AgentBindWxParam agentBindWxParam) throws Exception {
        // 判断当前用户是否已绑定微信
        UserAuthorize openIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                .eq(UserAuthorize::getSource, 3)
                .eq(UserAuthorize::getUserId, LoginUtil.getUserId())
                .eq(UserAuthorize::getType, 2));
        if (ObjectUtil.isNotNull(openIdAuthorize)) {
            throw new BusinessException(500, "当前账号已绑定其它微信号，如需换绑请联系平台客服");
        }
        WxAppLoginVo wxAppLoginVo = wxAgentAppUtil.login(agentBindWxParam.getAuthCode());
        if (wxAppLoginVo.getOpenid() == null) {
            throw new BusinessException(500, "微信授权失败");
        }
        openIdAuthorize = new UserAuthorize();
        openIdAuthorize.setUserId(LoginUtil.getUserId());
        openIdAuthorize.setType(2);
        openIdAuthorize.setSource(3);
        openIdAuthorize.setContent(wxAppLoginVo.getOpenid());
        openIdAuthorize.setNickname(wxAppLoginVo.getNickname());
        openIdAuthorize.setHeadImgUrl(wxAppLoginVo.getHeadimgurl());
        userAuthorizeMapper.insert(openIdAuthorize);

        // 如果unionID不为空还需要保存unionID信息
        if (StringUtil.isNotBlank(wxAppLoginVo.getUnionid())) {
            // 先判断是否已存在信息
            UserAuthorize unionIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                    .eq(UserAuthorize::getSource, 3)
                    .eq(UserAuthorize::getUserId, LoginUtil.getUserId())
                    .eq(UserAuthorize::getType, 3));
            if (ObjectUtil.isNull(unionIdAuthorize)) {
                // 不存在则保存
                unionIdAuthorize = new UserAuthorize();
                unionIdAuthorize.setUserId(LoginUtil.getUserId());
                unionIdAuthorize.setType(3);
                unionIdAuthorize.setSource(3);
                unionIdAuthorize.setContent(wxAppLoginVo.getUnionid());
                userAuthorizeMapper.insert(unionIdAuthorize);
            } else {
                unionIdAuthorize.setContent(wxAppLoginVo.getUnionid());
                userAuthorizeMapper.updateById(unionIdAuthorize);
            }
        }

        // 获取用户信息
        User user = userMapper.selectById(LoginUtil.getUserId());

        if (StringUtil.isNotBlank(wxAppLoginVo.getNickname()) || StringUtil.isNotBlank(wxAppLoginVo.getHeadimgurl())) {
            if (StringUtil.isBlank(user.getNickname())) {
                user.setNickname(wxAppLoginVo.getNickname());
            }
            if (StringUtil.isBlank(user.getHeadImg()) || "https://yk-c-api.prc110.com/api-base/file/NGL6da117PCqnrJIndUlZrzSClXZF30Q".equals(user.getHeadImg())) {
                user.setHeadImg(wxAppLoginVo.getHeadimgurl());
            }
            userMapper.updateById(user);
        }
        return wxAppLoginVo.getNickname();
    }

    @Override
    public boolean getMchWxPhone(String code) throws Exception {
        // 从微信接口获取手机号
        WxPhoneVo wxPhoneVo = wxMchAppUtil.getWxPhone(code);
        // 先判断当前手机号是否是商家
        User merchantUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getMobile, wxPhoneVo.getPhone_info().getPurePhoneNumber()));
        if (merchantUser == null) {
            throw new BusinessException(500, "当前手机号还未成为商家，请联系平台客服成为商家");
        }
        Merchant merchant = merchantMapper.selectOne(Wrappers.lambdaQuery(Merchant.class)
                .eq(Merchant::getUserId, LoginUtil.getUserId()));
        if (merchant == null) {
            throw new BusinessException(500, "当前手机号还未成为商家，请联系平台客服成为商家");
        }
        // 判断当前手机号用户是否已绑定微信
        // 先判断是否已存在信息
        UserAuthorize openIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                .eq(UserAuthorize::getSource, 2)
                .eq(UserAuthorize::getUserId, merchantUser.getId())
                .eq(UserAuthorize::getType, 2));
        if (ObjectUtil.isNotNull(openIdAuthorize)) {
            throw new BusinessException(500, "当前手机号已绑定其它微信号，如需换绑请联系平台客服");
        }
        // 将微信绑定信息切换到新的手机号用户
        openIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                .eq(UserAuthorize::getSource, 2)
                .eq(UserAuthorize::getUserId, LoginUtil.getUserId())
                .eq(UserAuthorize::getType, 2));
        if (ObjectUtil.isNull(openIdAuthorize)) {
            throw new BusinessException(500, "获取微信授权信息异常");
        }
        // 直接替换掉用户ID
        openIdAuthorize.setUserId(merchantUser.getId());
        userAuthorizeMapper.updateById(openIdAuthorize);

        // 判断是否有对应的unionID
        UserAuthorize unionIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                .eq(UserAuthorize::getSource, 2)
                .eq(UserAuthorize::getUserId, LoginUtil.getUserId())
                .eq(UserAuthorize::getType, 3));
        if (ObjectUtil.isNotNull(unionIdAuthorize)) {
            // 直接替换掉
            unionIdAuthorize.setUserId(merchantUser.getId());
            userAuthorizeMapper.updateById(unionIdAuthorize);
        }

        // 获取登录用户信息
        LoginUserInfoVo loginUserInfoVo = LoginUtil.getLoginUserInfoVo();

        // 更新用户信息
        BeanUtils.copyProperties(merchantUser, loginUserInfoVo);
        // 处理不同端登录需要不同信息问题
        loginSourceContext.login(loginUserInfoVo, 2);

        redisUtil.set(TokenUtil.getToken(), loginUserInfoVo, 30 * 24 * 60 * 60);

        return true;
    }

    @Override
    public boolean getAgentWxPhone(String code) throws Exception {
//        // 从微信接口获取手机号
//        WxPhoneVo wxPhoneVo = wxAgentAppUtil.getWxPhone(code);
//        // 获取当前登录用户信息
//        User user = userMapper.selectById(LoginUtil.getUserId());
//        // 判断手机号是否为空，为空则更新
//        if (StringUtil.isBlank(user.getMobile())) {
//            user.setMobile(wxPhoneVo.getPhone_info().getPurePhoneNumber());
//            userMapper.updateById(user);
//        } else {
//            if (!user.getMobile().equals(wxPhoneVo.getPhone_info().getPurePhoneNumber())) {
//                throw new BusinessException("当前微信号已绑定其它手机号");
//            }
//        }
        return true;
    }

    @Override
    public String getAppCode(GetAppCodeParam getAppCodeParam) throws Exception {
        // 根据类型获取不同二维码
        byte[] bytes = null;
        if (getAppCodeParam.getType() == 1) {
            bytes = wxAppUtil.getAppCode(getAppCodeParam);
        } else if (getAppCodeParam.getType() == 2) {
            bytes = wxAppUtil.getUnlimitedAppCode(getAppCodeParam);
        } else if (getAppCodeParam.getType() == 3) {
            bytes = wxAppUtil.getAppQRCode(getAppCodeParam);
        }
        if (bytes == null || bytes.length < 1) {
            throw new BusinessException("获取小程序码失败");
        }
        // 目标目录
        String outputDir = "./resources/files/appcode";

        // 创建目录（如果不存在）
        File directory = new File(outputDir);
        if (!directory.exists()) {
            directory.mkdirs();
        }

        // 生成图片文件的完整路径
        String outputFileName = RandomStringUtils.randomAlphanumeric(32);
        String outputFilePath = outputDir + "/" + outputFileName + ".png";

        // 将字节数组写入到图片文件中
        try (FileOutputStream fos = new FileOutputStream(outputFilePath)) {
            fos.write(bytes);
        }

        return "https://yk-c-api.prc110.com/api-user/appCode/download/" + outputFileName;
    }

    @Override
    public void download(HttpServletResponse response, String code) throws Exception {
        File downloadFile = new File("./resources/files/appcode/" + code + ".png");
        if (!downloadFile.exists() || downloadFile.length() == 0) {
            throw new BusinessException(500, "文件不存在");
        }

        // 确定文件的Content-Type
        String mimeType = Files.probeContentType(downloadFile.toPath());
        if (mimeType == null) {
            mimeType = "application/octet-stream"; // 默认类型
        }

        response.setContentType(mimeType);
        response.addHeader("Content-Length", String.valueOf(downloadFile.length()));
        response.addHeader("Content-Disposition", "attachment; filename=\"" + code + ".png\"");

        try (InputStream is = new FileInputStream(downloadFile);
             OutputStream os = response.getOutputStream()) {

            IOUtils.copy(is, os);
            os.flush(); // 确保数据已写入输出流
        } catch (IOException e) {
            log.info("下载图片发生IO异常");
            e.printStackTrace();
            throw new BusinessException(500, "文件下载失败");
        } catch (Exception e) {
            log.info("下载图片发生异常");
            e.printStackTrace();
            throw new BusinessException(500, "文件下载失败");
        }
    }
}
